﻿using Google.Protobuf.WellKnownTypes;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Modules.Base;
using Modules.CheckIn;
using Modules.Device;
using Modules.Device.Entitys;
using Modules.FaceScan;
using Modules.FaceScan.Entitys;
using Modules.Person;
using Modules.Project.Entitys;
using Modules.Project.Repositories;
using MySqlX.XDevAPI;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Org.BouncyCastle.Asn1.Crmf;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Entity;
using PmSoft.Exceptions;
using PmSoft.FileStorage;
using PmSoft.Utilities;
using PmSoft.Utilities.Sm4;
using RestSharp;
using System.Configuration;
using System.Web;
using static Modules.CheckIn.CheckInDetailConstants;
using static Modules.Device.CheckInDeviceConstants;

namespace Modules.Project
{
    [UseDI(ServiceLifetime.Scoped)]
    public class ProjectGroupService
    {
        private readonly ProjectGroupRepository projectGroupRepository;
        private readonly ProjectGroupMemberService projectGroupMemberService;
        private readonly PersonService personService;
        private readonly IConfiguration configuration;
        private readonly IFileStorage fileStorage;
        private readonly CheckinDeviceService checkinDeviceService;
        private readonly CheckinDeviceCommandService checkinDeviceCommandService;
        private readonly IApplicationContext applicationContext;

        public ProjectGroupService(ProjectGroupRepository projectGroupRepository,
            ProjectGroupMemberService projectGroupMemberService,
            IConfiguration configuration,
            PersonService personService,
            IFileStorage fileStorage,
            CheckinDeviceService checkinDeviceService,
            CheckinDeviceCommandService checkinDeviceCommandService,
            IApplicationContext applicationContext
            )
        {
            this.projectGroupRepository = projectGroupRepository;
            this.projectGroupMemberService = projectGroupMemberService;
            this.personService = personService;
            this.configuration = configuration;
            this.checkinDeviceService = checkinDeviceService;
            this.checkinDeviceCommandService = checkinDeviceCommandService;
            this. fileStorage=fileStorage;
            this.applicationContext= applicationContext;
        }

        /// <summary>
        /// 新增班组
        /// </summary>
        /// <param name="entity"></param>
        /// <exception cref="BusinessException"></exception>
        public void CreateProjectGroup(ProjectGroup entity)
        {
            if (entity.IsManagerGroup == true)
            {
                IEnumerable<ProjectGroup> projectCorps = projectGroupRepository.GetProjectGroupsByProjectId(entity.ProjectId).Where(a => a.IsManagerGroup == true && a.CorpId == entity.CorpId);
                if (projectCorps != null && projectCorps.Any() && projectCorps.Count() > 0)
                    throw new BusinessException($"当前参建单位，管理班组已存在，不能新增多个管理班组");
            }
            if (projectGroupRepository.ExistsByNameAndProjectId(entity.Name, entity.CorpId, entity.ProjectId))
            {
                throw new BusinessException($"班组名称：{entity.Name} 已存在，不能创建");
            }
            projectGroupRepository.Insert(entity);
        }

        /// <summary>
        /// 新增班组(已存在就不用创建)
        /// </summary>
        /// <param name="entity"></param>
        /// <exception cref="BusinessException"></exception>
        public void SilentCreateProjectGroup(ProjectGroup entity)
        {
            if (!projectGroupRepository.ExistsByNameAndProjectId(entity.Name, entity.CorpId, entity.ProjectId))
                projectGroupRepository.Insert(entity);
        }

        public void DeleteProjectGroups(IEnumerable<int> groupIds)
        {
            IEnumerable<ProjectGroupMember> projectGroupMembers = projectGroupMemberService.GetProjectGroupMembersByGroupIds(groupIds);
            foreach (int groupId in groupIds)
            {
                if (projectGroupMembers.Where(a => a.GroupId == groupId).Count() > 0)
                    throw new BusinessException($"选择的班组下有人员信息，不能删除");
                DeleteProjectGroup(groupId);
            }
        }

        /// <summary>
        /// 删除班组
        /// </summary>
        /// <param name="projectGroupId"></param>
        public void DeleteProjectGroup(int projectGroupId)
        {
            projectGroupRepository.DeleteByEntityId(projectGroupId);
        }

        public ProjectGroup? GetProjectGroup(int id)
        {
            return projectGroupRepository.Get(id);
        }

        public IPagedList<ProjectGroup> GetProjectGroups(ProjectGroupQuery query, int pageIndex, int pageSize)
        {
            return projectGroupRepository.GetProjectGroups(query, pageIndex, pageSize);
        }

        public IEnumerable<ProjectGroup> GetProjectGroups(IEnumerable<int> ids)
        {
            return projectGroupRepository.PopulateEntitiesByEntityIds(ids);
        }

        public void UpdateProjectGroup(ProjectGroup entity)
        {
            if (projectGroupRepository.ExistsByNameAndProjectId(entity.Name, entity.CorpId, entity.ProjectId, entity.GroupId))
                throw new BusinessException($"班组名称：{entity.Name} 已存在，不能创建");
            projectGroupRepository.Update(entity);
        }

        public IEnumerable<ProjectGroup> GetProjectGroupsByCordProjectId(int projectId, IEnumerable<int> corpIds)
        {
            return GetProjectGroupsByProjectId(projectId).Where(w => corpIds.Contains(w.CorpId));
        }

        public IEnumerable<ProjectGroup> GetProjectGroupsByProjectId(int projectId)
        {
            return projectGroupRepository.GetProjectGroupsByProjectId(projectId);
        }

        public ProjectGroup? GetProjectGroupByPjCorpName(int projectId, int corpId, string groupName)
        {
            return projectGroupRepository.GetProjectGroupByPjCorpName(projectId, corpId, groupName);
        }

        public IEnumerable<ProjectGroup> GetProjectGroupsByProjectId(ProjectCheckinCountQuery query)
        {
            var data = projectGroupRepository.GetProjectGroupsByProjectId(query.ProjectId ?? 0);
            if (!string.IsNullOrEmpty(query.GroupIds))
            {
                var groupIds = ValueUtility.ConvertToList<int>(query.GroupIds);
                data = data.Where(a => groupIds.Contains(a.GroupId));
            }
            return data;
        }

        /// <summary>
        /// 获取项目的所有班组
        /// </summary>
        /// <param name="projectId">项目ID</param>
        /// <param name="keywords">搜索关键字（班组或人员名称）</param>
        /// <returns></returns>
        public IEnumerable<ProjectGroup> SearchGoups(int projectId, string keywords)
        {
            return projectGroupRepository.SearchGoups(projectId, keywords);
        }

        /// <summary>
        /// 查询项目班组数量
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public int GetProjectGroupCount(ProjectCheckinCountQuery query)
        {
            return projectGroupRepository.GetProjectGroupCount(query);
        }

        public int OnSiteVerification(int personId, string pic, int projectId)
        {
            pic = pic.Split(",")[1];
            PersonInfo? personInfo = personService.GetPerson(personId);
            if (personInfo == null) throw new BusinessException("人员信息不存在");

            #region 人脸比对

            InternalCompareReq internalCompareReq = new()
            {
                IdCard = personInfo.CardNumber,
                PicData = pic
            };
            RestRequest request = new RestRequest("/api/v1/Recognition/InternalCompare", RestSharp.Method.Post);
            request.AddBody(internalCompareReq, ContentType.Json);
            var result = ExecuteAsync<ServiceResult<FaceCompareResult>>(request).GetAwaiter().GetResult();
            if (result == null)
                throw new ArgumentNullException(nameof(result));

            if (!result.success)
                throw new BusinessException(result.msg);

            if (result.data == null)
                throw new ArgumentNullException(nameof(result.data));

            if (result.success == true)
            {
                FaceScanRecord record = new();
                record.ReferType = FaceScanReferType.ManagerPersonVerification;
                record.IdCard = personInfo.CardNumber;
                record.ScanCode = "-";
                record.ConfirmTime = DateTime.Now;
                record.IsConfirmed = true;
                record.DataSource = 数据来源.PC;
                record.IsPassed = result.data.IsPass;
                record.VerifyTime = DateTime.Now;
                record.CameraPhoto = $"{personInfo.CardNumber}/Appauth_{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.jpg";

                #region 上传到minio
                var camFaceData = Base64Utilities.ConverBase64(pic);
                fileStorage.PutFileAsync(FileBuckets.Person, record.CameraPhoto, camFaceData).GetAwaiter().GetResult(); ;

                #endregion 上传到minio

                applicationContext.GetService<FaceScanRecordService>().Create(record);
                #region 下发人员信息到设备
                if (result.data.IsPass)
                {
                    IEnumerable<CheckinDevice> devices = checkinDeviceService.GetProjectCheckinDevicesByProjectId(projectId);
                    foreach (var device in devices)
                    {
                        CheckinDeviceCommand log = new CheckinDeviceCommand()
                        {
                            Name = 考勤机命令.人员进场后下发.GetDescription(),
                            Code = 考勤机命令.人员进场后下发,
                            MessageId = Guid.NewGuid().ToString(),
                            DeviceCode = device.Code,
                            Status = 命令下发状态.待下发,
                            IsAuto = true
                        };
                        checkinDeviceCommandService.Send(log, device, new List<PersonInfo>() { personInfo });
                    }
                    return record.Id;
                }
                #endregion 下发人员信息到设备
            }
             return 0;

            #endregion 人脸比对
        }

        #region 私有方法

        private object Execute(RestRequest request)
        {
            using RestClient client = new RestClient(configuration.GetValue<string>("FaceRecognitionWebUrl"));

            var response = client.Execute<ServiceResult>(request);

            if (response.ErrorException != null)
            {
                return new ServiceResult { msg = "实名制平台内部通讯失败" };
            }
            return response.Content;
        }


        /// <summary>
        /// 执行http请求
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <exception cref="BusinessException"></exception>
        public async Task<TResult?> ExecuteAsync<TResult>(RestRequest request)
        {
            using RestClient client = new RestClient(configuration.GetValue<string>("FaceRecognitionWebUrl"));
            var response = await client.ExecuteAsync<TResult>(request);

            if (response.ErrorException != null)
            {
                throw new BusinessException("内部通讯失败");
            }
            return response.Data;
        }
        #endregion 私有方法
    }
}